/*
 * TacticaLechal.java
 * Jorge Alvaro Rey
 *
 */

package futbol.tacticas.concursantes2007.Lechal;

import futbol.General;
import futbol.tacticas.Comando;
import futbol.tacticas.ComandoGolpearBola;
import futbol.tacticas.ComandoIrA;
import futbol.tacticas.ComandoTiroAPuerta;
import futbol.tacticas.SituacionJugadores;
import futbol.tacticas.concursantes.Tactica;

import java.awt.Color;
import java.awt.Point;
import java.util.Vector;

/**
 * @author Jorge Alvaro Rey
 */
public class TacticaLechal implements Tactica {
    
    protected int nGolesMios=0;
    protected int nGolesContrario=0;
    protected int nXBolaAnt=0;
    protected int nYBolaAnt=0;
    
    protected SituacionJugadores situacionJugadoresAnt=null;
    protected double[] velocidadContrario = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
    protected double[] velocidad = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3};
    protected double vMax = 3;

    protected final static int CTE_FUERZA = 30;
    protected final static int CTE_NUMERO = 5;
    protected final static int GOL = 100;
    protected final static double ANGULO = 2.*Math.PI/5.;
    protected final static int LIMITE_TIRO = 65;
    protected final static int LIMITE_POSIBILIDADES = 500;
    
    /** Creates a new instance of TacticaLechal */
    public TacticaLechal() {
    }
    
    private int nValores[][]={
        {-150,   0, 6},  // Jugador 1[0]
        {-120, -30, 7},  // Jugador 2[1]
        {-120,  30, 7},  // Jugador 3[2]
        {-100,   0, 6},  // Jugador 4[3]
        { -20,   0, 6},  // Jugador 5[4]
        {  20,   0, 4},  // Jugador 6[5] (Centro)
        {  20,  70, 4},  // Jugador 7[6]
        {  20, -70, 5},  // Jugador 8[7]
        {  85,  60, 7},  // Jugador 9[8]
        {  85, -60, 7},  // Jugador 10[9]
        { 110,   0, 7},  // Jugador 11[10] (Penalti)
    };
    
    public Color getColor1() {
        return Color.BLUE;
    }

    public Color getColor2() {
        return Color.BLUE;
    }

    public Color getColorNumero() {
        return Color.CYAN;
    }

    public String getNombre() {
        return "Lechal";
    }

    public int getXInicial(int n) {
        if(nValores[n][0]>=0)
            return 160;
        else
            return nValores[n][0];
    }

    public int getYInicial(int n) {
        return nValores[n][1];
    }

    public int getFuerza(int n) {
        return nValores[n][2];
    }

    public Vector<Comando> getComandos(SituacionJugadores sj) {
        Vector<Comando> com=new Vector();
        
        //Posicionamiento
        for (int n=0; n<11; n++)
            com.add(new ComandoIrA(n, nValores[n][0], nValores[n][1]));

        Point bola=sj.getBola();
        Point jugadores[]=sj.getMisJugadores();
        Point contrarios[]=sj.getContrario();
        
        // Marcador
        int nXBola = (int)bola.getX();
        int nYBola = (int)bola.getY();
        if (nXBolaAnt>150 && nXBola<40)
        {
            nGolesMios++;
        }
        else if (nXBolaAnt<-150 && nXBola>-40)
        {
            nGolesContrario++;
        }
        // Calcular fuerza/velocidad de los contrarios
        else if(situacionJugadoresAnt!=null)
        {
            Point[] actualContrario=sj.getContrario();
            Point[] previoContrario=situacionJugadoresAnt.getContrario();
            for(int i=0; i<11; i++)
            {
                double distanciaContrario=General.getDistancia(actualContrario[i].getX(), actualContrario[i].getY(), previoContrario[i].getX(), previoContrario[i].getY());
                if(distanciaContrario>velocidadContrario[i])
                {
                    velocidadContrario[i]=distanciaContrario;
                    if(distanciaContrario>vMax)
                        vMax=distanciaContrario;
                    //System.out.println("Jugador "+i+" tiene velocidad "+distancia);
                }
            }
            Point[] actual=sj.getMisJugadores();
            Point[] previo=situacionJugadoresAnt.getMisJugadores();
            for(int i=0; i<11; i++)
            {
                double distancia=General.getDistancia(actual[i].getX(), actual[i].getY(), previo[i].getX(), previo[i].getY());
                if(distancia>velocidad[i])
                {
                    velocidad[i]=distancia;
                    if(distancia>vMax)
                        vMax=distancia;
                }
            }
        }
        situacionJugadoresAnt=sj;
        
        // Donde llegara la bola
        double[] finalBola = posicionFinalBola(nXBolaAnt, nYBolaAnt, nXBola, nYBola);
        nXBolaAnt=nXBola;
        nYBolaAnt=nYBola;
        
        //Mejorar defensa
        if (!sj.estoyMasCercaDeBola() || bola.getX()<0){
            for (int n=1; n<4; n++){
                int nJC=sj.getContrarioMasCerca(getXInicial(n), getYInicial(n));
                com.add(new ComandoIrA(n, contrarios[nJC].getX()+1, contrarios[nJC].getY()));
            }
        }

        //Movimiento portero
        int y=(int)(bola.getY()/2);
        if (y<-20) y=-20;
        if (y>20) y=20;
        com.add(new ComandoIrA(0, nValores[0][0], y));
        
        //Movimiento mas cercano a la bola
        int nJug=sj.getMasCercanoDeBola();
        com.add(new ComandoIrA(nJug, bola.getX(), bola.getY()));
        int nJug2=sj.getMiJugadorMasCerca(finalBola[0], finalBola[1]);
        com.add(new ComandoIrA(nJug2, finalBola[0], finalBola[1]));
        for(int i=0; i<11; i++)
        {
            Point j = sj.getMisJugadores()[i];
            if(General.getDistancia(j.getX(), j.getY(), finalBola[0], finalBola[1])<(finalBola[2]+(i==0 ? 0 : 1))*velocidad[i])
            {
                com.add(new ComandoIrA(i, bola.getX(), bola.getY()));
            }
        }

        lanzarBolaMejor(sj, com);
        
        return com;
    }
    
    private double[] posicionFinalBola(double xAnt, double yAnt, double x, double y)
    {
        double distancia = Math.round(General.getDistancia(xAnt, yAnt, x, y));
        int turnos = 0;
        if(distancia>1)
        do
        {
            double xAux = x;
            double yAux = y;
            x = x+(x-xAnt)*(distancia-1)/(distancia);
            y = y+(y-yAnt)*(distancia-1)/(distancia);
            xAnt = xAux;
            yAnt = yAux;
            
            if (x>=160 && y>-30 && y<30) return new double[]{x, y, turnos};
            if (x<=-160 && y>-30 && y<30) return new double[]{x, y, turnos};

            // Corregir
            if (x>160){
                x=320-x;  //160 - (x-160)
                xAnt=320-xAnt;  //160 - (x-160)
            }
            if (x<-160){
                x=-320-x; //-160 + (-160-x)
                xAnt=-320-xAnt; //-160 + (-160-x)
            }
            if (y>120){
                y=240-y; //120 - (x-120)
                yAnt=240-yAnt; //120 - (x-120)
            }
            if (y<-120){
                y=-240-y;  //-120 + (-120-x)
                yAnt=-240-yAnt;  //-120 + (-120-x)
            }
            distancia = General.getDistancia(xAnt, yAnt, x, y);
            turnos++;
        } while(distancia>=10);
        return new double[]{x, y, turnos};
    }
    
    private int heuristica(SituacionJugadores sj, int x, int y, int jugador) {
        
        float fHeu = 0;
        
        Point bola = sj.getBola();
        double angulo = General.getAngulo(bola.getX(), bola.getY(), x, y);
        double nextX, nextY;
        
        double nDis=General.getDistancia(bola.getX(), bola.getY(), x, y);
        double nGrado = 100.;
        if (nDis<50) nGrado=(int)(nDis*2);

        nextX = bola.getX()+3.*nGrado/100.*Math.cos(angulo)*((double)nValores[jugador][2]);
        nextY = bola.getY()+3.*nGrado/100.*Math.sin(angulo)*((double)nValores[jugador][2]);
        double[] posBola = posicionFinalBola(bola.getX(), bola.getY(), nextX, nextY);
        
        // Goles
        if (x>=160 && y>-30 && y<30 && hayAngulo(angulo))
            fHeu -= GOL;
        if (x<=-160 && y>-30 && y<30)
            fHeu += GOL;

        // Cuanto mas lejos de mi porteria, mejor (menor heuristica)
        fHeu -= 2*General.getDistancia(posBola[0], posBola[1], -140, 0);
        
        // Cuanto mas lejos de la porteria contraria, peor (mayor heuristica)
        fHeu += General.getDistancia(posBola[0], posBola[1], +110, 0);
        
        for(int n=0; n<11; n++)
        {
            // Por cada uno de mis jugadores que llegue a la bola, mejorar la heuristica (restar)
            Point jN = sj.getMisJugadores()[n];
            if(General.getDistancia(posBola[0], posBola[1], jN.getX(), jN.getY())<(posBola[2]-1)*velocidad[n])
                fHeu -= ((vMax-velocidad[n])/vMax*7+4) * CTE_FUERZA + n * CTE_NUMERO;
            
            // Por cada uno de los contrarios que llegue a la bola, empeorar la heuristica (sumar)
            Point jN_contrario = sj.getContrario()[n];
            if(General.getDistancia(posBola[0], posBola[1], jN_contrario.getX(), jN_contrario.getY())<posBola[2]*velocidadContrario[n])
                fHeu += (((vMax-velocidadContrario[n])/vMax*7+4) * CTE_FUERZA + n * CTE_NUMERO);
        }
        return (int)fHeu;
    }
    
    private void lanzarBolaMejor(SituacionJugadores sj, Vector<Comando> com){
        Point bola=sj.getBola();
        
        Point jugadores[]=sj.getMisJugadores();
        double angulo=Math.abs(General.getAngulo(bola.getX(), bola.getY(), 162, 5));
        boolean hayAngulo = hayAngulo(angulo);
        for(int n=0; n<11; n++) {
            int nHeuMejor=9999999;
            int xMej=0, yMej=0;
            int x=0, y=0, nHeu;
            for (int i=0; i<(11+LIMITE_POSIBILIDADES); i++) {
                if(i<11)
                {
                    x=(int)sj.getMisJugadores()[i].getX();
                    y=(int)sj.getMisJugadores()[i].getY();
                }
                else
                {
                    x=(int)(Math.random()*360)-160;
                    y=(int)(Math.random()*260)-130;
                }
                nHeu=heuristica(sj, x, y, n);
                if (nHeuMejor>nHeu) {
                    nHeuMejor=nHeu;
                    xMej=x;
                    yMej=y;
                }
            }
            
            Point jN = sj.getMisJugadores()[n];
            if(jugadores[n].getX()>=LIMITE_TIRO && nValores[n][2]>6 && hayAngulo)
                com.add(new ComandoGolpearBola(n, 162, 5));
            else
                com.add(new ComandoGolpearBola(n, xMej, yMej));
        }
    }

    protected boolean hayAngulo(double angulo)
    {
        return angulo<ANGULO || angulo>2*Math.PI-ANGULO;
    }
}
